package org.exhibitj.automation.agents;

import java.awt.AWTException;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.lang.reflect.Field;

import org.exhibitj.automation.Agent;

public class RobotAgent implements Agent {

	private Robot robot;

	public RobotAgent() {
		try {
			robot = new Robot();
		} catch (AWTException e) {
			e.printStackTrace();
		}
	}

	public void moveToLocation(int x, int y) {
		while (true) {
			Point currentLocation = MouseInfo.getPointerInfo().getLocation();

			Point location = new Point(x, y);
			if (currentLocation.equals(location)) {
				break;
			}

			int xJump = amountToJump(x, currentLocation.x);
			int yJump = amountToJump(y, currentLocation.y);

			currentLocation.x += (currentLocation.x > x) ? -xJump : currentLocation.x < x ? +xJump : 0;
			currentLocation.y += (currentLocation.y > y) ? -yJump : currentLocation.y < y ? +yJump : 0;
			robot.mouseMove(currentLocation.x, currentLocation.y);
			robot.delay(20);
		}
	}

	private int amountToJump(int desired, int actual) {
		int xJump = 1;
		if (differenceMoreThan(25, desired, actual)) {
			xJump = 10;
		} else if (differenceMoreThan(10, desired, actual)) {
			xJump = 5;
		}
		return xJump;
	}

	private boolean differenceMoreThan(int amount, int first, int second) {
		int difference = Math.abs(first - second);
		return difference > amount;
	}

	@Override
	public void clickLeftMouseButton() {
		clickMouseButton(InputEvent.BUTTON1_DOWN_MASK);
	}

	private void clickMouseButton(int buttonMask) {
		robot.mousePress(buttonMask);
		robot.delay(100);
		robot.mouseRelease(buttonMask);
	}

	@Override
	public void delay(int forNMilliseconds) {
		robot.delay(forNMilliseconds);
	}

	@Override
	public void pressKey(char character) {
		int key = getKey(character);
		robot.keyPress(key);
	}

	private int getKey(char character) {
		String key = character + "";
		try {
			Field field = KeyEvent.class.getField("VK_" + key.toUpperCase());
			return ((Integer)field.get(null)).intValue();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
		throw new RuntimeException("Unknown character [" + character + "]");
	}

	@Override
	public void releaseKey(char character) {
		int key = getKey(character);
		robot.keyRelease(key);
	}
}
